1   /*
2    * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.
8    *
9    * This code is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12   * version 2 for more details (a copy is included in the LICENSE file that
13   * accompanied this code).
14   *
15   * You should have received a copy of the GNU General Public License version
16   * 2 along with this work; if not, write to the Free Software Foundation,
17   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18   *
19   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20   * or visit www.oracle.com if you need additional information or have any
21   * questions.
22   */
23  
24  /**
25   *  @test
26   *  @bug 4628726
27   *  @summary Test class redefinition - method data line numbers and local vars,
28   *
29   *  @author Robert Field
30   *
31   *  @library ..
32   *  @run build TestScaffold VMConnection TargetListener TargetAdapter
33   *  @run compile -g RedefineTest.java
34   *  @run shell RedefineSetUp.sh
35   *  @run main RedefineTest -repeat 3
36   *  @run main RedefineTest
37   */
38  import com.sun.jdi.*;
39  import com.sun.jdi.event.*;
40  import com.sun.jdi.request.*;
41  import java.util.*;
42  import java.io.*;
43  
44      /********** target program **********/
45  
46  class RedefineTarg {
47      public static void main(String[] args){
48          RedefineSubTarg.stemcp();
49          RedefineSubTarg sub = new RedefineSubTarg();
50          sub.bottom();
51          RedefineSubTarg.stnemcp();
52          RedefineSubTarg.stemcp();
53      }
54  }
55  
56      /********** test program **********/
57  
58  public class RedefineTest extends TestScaffold {
59      static int redefineRepeat = 1;
60      int bpCnt = 0;
61  
62      // isObsolete, linenumber, lv name, lv value, lv isArg
63      String[] before = {
64      "+ 3",
65      "+ 6 eights 888 T",
66      "+ 11 rot 4 F",
67      "+ 15",
68      "+ 20 myArg 56 T paramy 12 F",
69      "+ 24",
70      "+ 28",
71      "+ 33" };
72      String[] after = {
73      "+ 5",
74      "O",
75      "O",
76      "+ 16",
77      "+ 21 whoseArg 56 T parawham 12 F",
78      "+ 25",
79      "O",
80      "+ 34" };
81      String[] shorter = {
82      "+ 5",
83      "+ 9 eights 88 T",
84      "+ 13",
85      "+ 16",
86      "+ 21 whoseArg 56 T parawham 12 F",
87      "+ 25" };
88      String[] refresh = {
89      "+ 5",
90      "+ 9 eights 88 T",
91      "+ 13",
92      "+ 16",
93      "+ 21 whoseArg 56 T parawham 12 F",
94      "+ 25",
95      "+ 29",
96      "+ 34" };
97      int[] bps = {7, 12, 16, 21, 25, 30, 34};
98      String[][] bpPlaces = {
99          {"+ 16"},
100         {"+ 21 myArg 56 T paramy 12 F"},
101         {"+ 25"},
102         {"+ 34"} };
103 
104     static String[] processArgs(String args[]) {
105         if (args.length > 0 && args[0].equals("-repeat")) {
106             redefineRepeat = Integer.decode(args[1]).intValue();
107             String[] args2 = new String[args.length - 2];
108             System.arraycopy(args, 2, args2, 0, args.length - 2);
109             return args2;
110         } else {
111             return args;
112         }
113     }
114 
115     RedefineTest (String args[]) {
116         super(args);
117     }
118 
119     public static void main(String[] args)      throws Exception {
120         new RedefineTest(processArgs(args)).startTests();
121     }
122 
123 
124     /********** event handlers **********/
125 
126     public void breakpointReached(BreakpointEvent event) {
127         println("Got BreakpointEvent - " + event);
128         try {
129             checkFrames(event.thread(), bpPlaces[bpCnt++]);
130             if (bpCnt >= bpPlaces.length) {
131                 eventRequestManager().deleteAllBreakpoints();
132             }
133         } catch (Exception exc) {
134             failure("FAIL: breakpoint checking threw " + exc);
135         }
136     }
137 
138     /********** test assists **********/
139 
140     // isObsolete, linenumber, lv name, lv value, lv isArg
141     // equals: ref type (always), method (not obsolete)
142     void checkFrames(ThreadReference thread, String[] matchList) throws Exception {
143         for (int i = 0; i < matchList.length; ++i) {
144             String match = matchList[i];
145             StackFrame frame = thread.frame(i);
146             Location loc = frame.location();
147             ReferenceType refType = loc.declaringType();
148             Method meth = loc.method();
149             String errInfo = "\nframe " + i + ": " + loc + "\n  match: " + match;
150             if (!findReferenceType("RedefineSubTarg").equals(refType)) {
151                  failure("FAIL: Bad reference type - " + errInfo);
152                  return; // might be bad class, but might have run past bottom
153             }
154             StringTokenizer st = new StringTokenizer(match);
155             boolean expectObs = st.nextToken().equals("O");
156             println("Frame " + i + ": " + meth);
157             if (meth.isObsolete()) {
158                 if (!expectObs) {
159                     failure("FAIL: Method should NOT be obsolete - " + errInfo);
160                 }
161             } else {
162                 if (expectObs) {
163                     failure("FAIL: Method should be obsolete - " + errInfo);
164                     break; // no more data to read
165                 }
166                 if (!findMethod(refType, meth.name(), meth.signature()).equals(meth)) {
167                     failure("FAIL: Non matching method - " + errInfo);
168                 }
169                 int line = loc.lineNumber();
170                 if (line != Integer.parseInt(st.nextToken())) {
171                     failure("FAIL: Unexpected line number: " + errInfo);
172                 }
173                 // local var matching
174                 int lvCnt = 0;
175                 while (st.hasMoreTokens()) {
176                     ++lvCnt;
177                     String lvName = st.nextToken();
178                     int lvValue = Integer.parseInt(st.nextToken());
179                     boolean isArg = st.nextToken().equals("T");
180                     LocalVariable lv = frame.visibleVariableByName(lvName);
181                     if (lv == null) {
182                         failure("FAIL: local var not found: '" + lvName +
183                                 "' -- " + errInfo);
184                     } else {
185                         Value val = frame.getValue(lv);
186                         int ival = ((IntegerValue)val).value();
187                         if (ival != lvValue) {
188                             failure("FAIL: expected value: '" + lvValue +
189                                     "' got: '" + ival + "' -- " + errInfo);
190                         }
191                         if (lv.isArgument() != isArg) {
192                             failure("FAIL: expected argument: '" + isArg +
193                                     "' got: '" + lv.isArgument() + "' -- " + errInfo);
194                         }
195                     }
196                 }
197                 List locals = frame.visibleVariables();
198                 if (locals.size() != lvCnt) {
199                         failure("FAIL: expected '" + lvCnt +
200                                 "' locals were '" + locals.size() +
201                                 "' -- " + errInfo + "' -- " + locals);
202                 }
203             }
204         }
205     }
206 
207 
208     void doRedefine(String fileName) throws Exception {
209         File phyl = new File(fileName);
210         byte[] bytes = new byte[(int)phyl.length()];
211         InputStream in = new FileInputStream(phyl);
212         in.read(bytes);
213         in.close();
214 
215         Map map = new HashMap();
216         map.put(findReferenceType("RedefineSubTarg"), bytes);
217 
218         try {
219             for (int i = 0; i < redefineRepeat; ++i) {
220                 vm().redefineClasses(map);
221             }
222         } catch (Exception thr) {
223             failure("FAIL: unexpected exception: " + thr);
224         }
225     }
226 
227     ThreadReference toTop() {
228         BreakpointEvent bpe = resumeTo("RedefineSubTarg", "top", "()V");
229         return bpe.thread();
230     }
231 
232     void setBP(int line) {
233         try {
234             Location loc = findLocation(findReferenceType("RedefineSubTarg"), line);
235             final BreakpointRequest request =
236                 eventRequestManager().createBreakpointRequest(loc);
237             request.enable();
238         } catch (Exception exc) {
239             failure("FAIL: Attempt to set BP at line " + line + " threw " + exc);
240         }
241     }
242 
243     /********** test core **********/
244 
245     protected void runTests() throws Exception {
246 
247         startToMain("RedefineTarg");
248 
249         ThreadReference thread = toTop();
250 
251         println("------ Before Redefine ------");
252         checkFrames(thread, before);
253 
254         println("------ After Redefine ------");
255         doRedefine("Different_RedefineSubTarg.class");
256         checkFrames(thread, after);
257 
258         println("------ Static 2 ------");
259         toTop();
260         checkFrames(thread, shorter);
261 
262         println("------ Instance ------");
263         toTop();
264         checkFrames(thread, shorter);
265 
266         println("------ Re-entered ------");
267         toTop();
268         checkFrames(thread, refresh);
269 
270         println("------ Breakpoints ------");
271         doRedefine("RedefineSubTarg.class");
272         for (int i = 0; i < bps.length; ++i) {
273             setBP(bps[i]);
274         }
275 
276         /*
277          * resume the target listening for events
278          */
279         listenUntilVMDisconnect();
280 
281         if (bpCnt != bpPlaces.length) {
282             failure("FAIL: Wrong number of breakpoints encountered: " + bpCnt);
283         }
284 
285         /*
286          * deal with results of test
287          * if anything has called failure("foo") testFailed will be true
288          */
289         if (!testFailed) {
290             println("RedefineTest(method): passed");
291         } else {
292             throw new Exception("RedefineTest(method): failed");
293         }
294     }
295 }